package ntlmssp
import (
"bytes"
"encoding/base64"
"io"
"io/ioutil"
"net/http"
"strings"
)
func GetDomain (user string ) (string , string , bool ) {
domain := ""
domainNeeded := false
if strings .Contains (user , "\\" ) {
ucomponents := strings .SplitN (user , "\\" , 2 )
domain = ucomponents [0 ]
user = ucomponents [1 ]
domainNeeded = true
} else if strings .Contains (user , "@" ) {
domainNeeded = false
} else {
domainNeeded = true
}
return user , domain , domainNeeded
}
type Negotiator struct { http .RoundTripper }
func (l Negotiator ) RoundTrip (req *http .Request ) (res *http .Response , err error ) {
rt := l .RoundTripper
if rt == nil {
rt = http .DefaultTransport
}
reqauth := authheader (req .Header .Values ("Authorization" ))
if !reqauth .IsBasic () {
return rt .RoundTrip (req )
}
reqauthBasic := reqauth .Basic ()
body := bytes .Buffer {}
if req .Body != nil {
_, err = body .ReadFrom (req .Body )
if err != nil {
return nil , err
}
req .Body .Close ()
req .Body = ioutil .NopCloser (bytes .NewReader (body .Bytes ()))
}
req .Header .Del ("Authorization" )
res , err = rt .RoundTrip (req )
if err != nil {
return nil , err
}
if res .StatusCode != http .StatusUnauthorized {
return res , err
}
resauth := authheader (res .Header .Values ("Www-Authenticate" ))
if !resauth .IsNegotiate () && !resauth .IsNTLM () {
req .Header .Set ("Authorization" , string (reqauthBasic ))
io .Copy (ioutil .Discard , res .Body )
res .Body .Close ()
req .Body = ioutil .NopCloser (bytes .NewReader (body .Bytes ()))
res , err = rt .RoundTrip (req )
if err != nil {
return nil , err
}
if res .StatusCode != http .StatusUnauthorized {
return res , err
}
resauth = authheader (res .Header .Values ("Www-Authenticate" ))
}
if resauth .IsNegotiate () || resauth .IsNTLM () {
io .Copy (ioutil .Discard , res .Body )
res .Body .Close ()
u , p , err := reqauth .GetBasicCreds ()
if err != nil {
return nil , err
}
domain := ""
u , domain , domainNeeded := GetDomain (u )
negotiateMessage , err := NewNegotiateMessage (domain , "" )
if err != nil {
return nil , err
}
if resauth .IsNTLM () {
req .Header .Set ("Authorization" , "NTLM " +base64 .StdEncoding .EncodeToString (negotiateMessage ))
} else {
req .Header .Set ("Authorization" , "Negotiate " +base64 .StdEncoding .EncodeToString (negotiateMessage ))
}
req .Body = ioutil .NopCloser (bytes .NewReader (body .Bytes ()))
res , err = rt .RoundTrip (req )
if err != nil {
return nil , err
}
resauth = authheader (res .Header .Values ("Www-Authenticate" ))
challengeMessage , err := resauth .GetData ()
if err != nil {
return nil , err
}
if !(resauth .IsNegotiate () || resauth .IsNTLM ()) || len (challengeMessage ) == 0 {
return res , nil
}
io .Copy (ioutil .Discard , res .Body )
res .Body .Close ()
authenticateMessage , err := ProcessChallenge (challengeMessage , u , p , domainNeeded )
if err != nil {
return nil , err
}
if resauth .IsNTLM () {
req .Header .Set ("Authorization" , "NTLM " +base64 .StdEncoding .EncodeToString (authenticateMessage ))
} else {
req .Header .Set ("Authorization" , "Negotiate " +base64 .StdEncoding .EncodeToString (authenticateMessage ))
}
req .Body = ioutil .NopCloser (bytes .NewReader (body .Bytes ()))
return rt .RoundTrip (req )
}
return res , err
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .